package dev.ece.core.cells.model.base;

import org.lwjgl.opengl.GL11;

import com.bulletphysics.collision.shapes.BoxShape;
import com.bulletphysics.collision.shapes.CollisionShape;

import dev.ece.core.cells.model.AbstractModel;
import dev.ece.core.cells.model.ModelCollisionShape;
import dev.ece.core.texture.FBOS;
import dev.ece.core.vertex.VAO;
import dev.ece.core.vertex.VBO;
import dev.ece.util.lib.Vector2f;
import dev.ece.util.lib.Vector3f;
import dev.ece.util.tools.Camera;
import dev.ece.util.tools.NormalUtils;

public class BoxModel extends AbstractModel<Integer> implements ModelCollisionShape {

	
	private float width;
	
	private float height;
	
	private float length;
	
	private Vector3f[] vertice;
	
	private Vector2f[] uv;
	
	private Vector3f[] normals;
	
	private VBO verticeVBO;
	
	private VBO uvVBO;
	
	private VBO normalsVBO;
	
	private VAO vao;
	
	public BoxModel(float width, float height, float length) {
		this.width = width;
		this.height = height;
		this.length = length;
		this.setup();
	}
	
	public void setup() {
		vertice = createVertice();
		uv = createUV();
		normals = createNormals();
		
		verticeVBO = VBO.newInstance(vertice);
		uvVBO = VBO.newInstance(uv);
		normalsVBO = VBO.newInstance(normals);
	}
	
	@Override
	public CollisionShape createCollisionShape() {
		return new BoxShape(new javax.vecmath.Vector3f(
				this.getWidth() / 2, 
				this.getHeight() / 2, 
				this.getLength() / 2));
	}
	
	protected Vector3f[] createVertice() {
		Vector3f[] vertice = new Vector3f[36];
		int index = 0;
		float x = width / 2;
		float y = height / 2;
		float z = length / 2;
		//正面
		vertice[index ++] = new Vector3f(-x, y, z);
		vertice[index ++] = new Vector3f(-x, -y, z);
		vertice[index ++] = new Vector3f(x, y, z);
		vertice[index ++] = new Vector3f(x, y, z);
		vertice[index ++] = new Vector3f(-x, -y, z);
		vertice[index ++] = new Vector3f(x, -y, z);
		//后面
		vertice[index ++] = new Vector3f(x, y, -z);
		vertice[index ++] = new Vector3f(x, -y, -z);
		vertice[index ++] = new Vector3f(-x, y, -z);
		vertice[index ++] = new Vector3f(-x, y, -z);
		vertice[index ++] = new Vector3f(x, -y, -z);
		vertice[index ++] = new Vector3f(-x, -y, -z);
		//左
		vertice[index ++] = new Vector3f(-x, y, -z);
		vertice[index ++] = new Vector3f(-x, -y, -z);
		vertice[index ++] = new Vector3f(-x, y, z);
		vertice[index ++] = new Vector3f(-x, y, z);
		vertice[index ++] = new Vector3f(-x, -y, -z);
		vertice[index ++] = new Vector3f(-x, -y, z);
		//右
		vertice[index ++] = new Vector3f(x, y, z);
		vertice[index ++] = new Vector3f(x, -y, z);
		vertice[index ++] = new Vector3f(x, y, -z);
		vertice[index ++] = new Vector3f(x, y, -z);
		vertice[index ++] = new Vector3f(x, -y, z);
		vertice[index ++] = new Vector3f(x, -y, -z);
		//上
		vertice[index ++] = new Vector3f(x, y, z);
		vertice[index ++] = new Vector3f(x, y, -z);
		vertice[index ++] = new Vector3f(-x, y, z);
		vertice[index ++] = new Vector3f(-x, y, z);
		vertice[index ++] = new Vector3f(x, y, -z);
		vertice[index ++] = new Vector3f(-x, y, -z);
		//下
		vertice[index ++] = new Vector3f(x, -y, -z);
		vertice[index ++] = new Vector3f(x, -y, z);
		vertice[index ++] = new Vector3f(-x, -y, -z);
		vertice[index ++] = new Vector3f(-x, -y, -z);
		vertice[index ++] = new Vector3f(x, -y, z);
		vertice[index ++] = new Vector3f(-x, -y, z);
		return vertice;
	}
	
	protected Vector3f[] createNormals() {
		Vector3f[] normals = new Vector3f[36];
		int index = 0;
		for(int i=0; i<12; i++) {
			normals[index] = NormalUtils.buildNormal(vertice[index + 2], vertice[index] , vertice[index + 1], null);
			index ++;
			normals[index] = NormalUtils.buildNormal(vertice[index - 1], vertice[index] , vertice[index + 1], null);
			index ++;
			normals[index] = NormalUtils.buildNormal(vertice[index - 1], vertice[index] , vertice[index - 2], null);
			index ++;
		}
		return normals;
	}
	
	protected Vector2f[] createUV() {
		Vector2f[] uv = new Vector2f[36];
		int index = 0;
		for(int i=0; i< 6; i++) {
			uv[index ++] = new Vector2f(0, 0);
			uv[index ++] = new Vector2f(0, 1);
			uv[index ++] = new Vector2f(1, 0);
			uv[index ++] = new Vector2f(1, 0);
			uv[index ++] = new Vector2f(0, 1);
			uv[index ++] = new Vector2f(1, 1);
		}
		return uv;
	}
	
	@Override
	public void destroy() {
		if(vao != null) {
			vao.destroy();
		}
		vao = null;
		vertice = null;
		uv = null;
	}

	@Override
	public void onRenderDepthMap(Camera camera, Integer value) {
		vao.bind();
		GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, 36);
	}

	@Override
	public void onRenderAlpha(FBOS defer, Camera camera, Integer value) {
		onRenderDepthMap(camera, value);
	}

	@Override
	public void onInitialize() {
		vao = new VAO();
		vao.bind();
		vao.bindVertexArrayBuffer(verticeVBO, 3);
		vao.bindVertexArrayBuffer(uvVBO, 2);
		vao.bindVertexArrayBuffer(normalsVBO, 3);
		vao.finish();
		
		verticeVBO = null;
		uvVBO = null;
		normalsVBO = null;
	}

	@Override
	public void onRender(Camera camera, Integer value) {
		onRenderDepthMap(camera, value);
	}

	public float getWidth() {
		return width;
	}

	public float getHeight() {
		return height;
	}

	public float getLength() {
		return length;
	}

	public Vector3f[] getVertice() {
		return vertice;
	}

	public Vector2f[] getUv() {
		return uv;
	}

	public Vector3f[] getNormals() {
		return normals;
	}

}
